
#include "cs_t2cmanager.h"
#include <QStringList>
#include <QVariant>
#include <QDateTime>
#include "ProcessVariable.h"
#include "QueryMicroMan.h"


//-------------------------------------

T2CManager::T2CManager(QObject *parent) :
    QObject( parent ),
    thread( new QThread() ),
    qmm( new QueryMicroMan() )
{
    connect( this, SIGNAL(sgnConnect(QString,quint16)), qmm, SLOT(Connect(QString,quint16)));
    connect( this, SIGNAL(sgnDisconnect()), qmm, SLOT(Disconnect()));
    connect( this, SIGNAL(sgnExecCmd(QString)), qmm, SLOT(ExecCmd(QString)));
    connect( qmm, SIGNAL(updated(QString)), this, SLOT(sltQueryUpdated(QString)) );

    qmm->moveToThread( thread );
    thread->start();
}

//-------------------------------------

void T2CManager::ExecCmd( QString cmd )
{
    emit sgnExecCmd( cmd );
}

//-------------------------------------

void T2CManager::Connect( QString h, quint16 p )
{
    emit sgnConnect( h, p );
}

//-------------------------------------

void T2CManager::Disconnect()
{
    emit sgnDisconnect();
}

//-------------------------------------

ProcessVariable T2CManager::getVariable( quint64 idf, quint64 timeout )
{
    /*if( PVs.contains( idf ) )
        return PVs[ idf ];*/

    emit sgnExecCmd( QString( "ANM 0 ORG %1" ).arg( idf ) );

    ProcessVariable pv;
    pv.init();

    if( checkTimeout( timeout ) )
    {
        pv = parseAnswer( qmm->outStr );
        PVs.insert( idf, pv );
        emit valueUpdated( pv.idf );
    }
    return pv;
}

//-------------------------------------

bool T2CManager::waitForReady( quint64 timeout )
{
    emit sgnExecCmd( "T2C CPL" );

    ProcessVariable pv;
    pv.init();

    if( checkTimeout( timeout ) )
    {
        pv = parseAnswer( qmm->outStr );
        if( pv.cmd == NO_CMD_STR )
        {
            verInfo = pv.value.toString();
            return true;
        }
    }
    return false;
}

//-------------------------------------

void T2CManager::wait( quint64 & to )
{
    QTime t1;
    t1.start();
    QTime t2 = t1.addMSecs( to );
    while( t1 < t2 )
         t1.start();
}

//-------------------------------------

bool T2CManager::checkTimeout( quint64 & to )
{
    quint64 halfTO = to;
    halfTO /= 2;
    int cnt = 0;
    wait( halfTO );
    while( qmm->locked )
    {
        if( qmm->locked )
        {
            wait( halfTO );
            cnt++;
        }
        else
            break;
    }

    if( cnt <= 1 )
        return true;

    return false;
}

//-------------------------------------

ProcessVariable T2CManager::parseAnswer( QString & s )
{
    ProcessVariable pv;
    pv.init();

    if( s == TIMEOUTED_STR )
    {
        pv.value = QVariant( TIMEOUTED_STR );
        return pv;
    }

    QStringList tmp_sl = s.split(" ");

    if( s.contains( "Test-Version" ) )
    {
        pv.value = QVariant( s );
        pv.cmd = NO_CMD_STR;
    }

    if( tmp_sl.count() >= 7 && tmp_sl[0] == "DAT" )
    {
        pv.idf = tmp_sl[2].toULongLong();
        pv.type = tmp_sl[3];
        pv.value = QVariant( tmp_sl[4] );
        pv.time.setMSecsSinceEpoch( (qint64)( tmp_sl[6].toDouble()*1000 ) );
        pv.cmd.clear();
        for( int j=0; j < tmp_sl.count()-2; j++ )
            pv.cmd += ( tmp_sl[j] + ( j == tmp_sl.count()-3 ? "" : " " ) );

        QString status = tmp_sl[5];
        char symb;

        pv.s = ProcessVariable::OK;
        for( int i = 0; i < status.length(); i++ )
        {
            symb = status.at( i ).toAscii();

            switch( symb )
            {
                case 'N':
                    pv.s |= ProcessVariable::NotOK;
                    break;
                case 'T':
                    pv.s |= ProcessVariable::Test;
                    break;
                case 'G':
                    pv.s |= ProcessVariable::Blocked;
                    break;
                case 'B':
                    pv.s |= ProcessVariable::UserEntry;
                    break;
                case 'E':
                    pv.s |= ProcessVariable::Substituted;
                    break;
                case 'A':
                    pv.s |= ProcessVariable::Queried;
                    break;
                case 'R':
                    pv.s |= ProcessVariable::Reserved;
                    break;
            }
        }
    }
    int cp =1;
    return pv;
}

//-------------------------------------

ProcessVariable T2CManager::sltQueryUpdated( QString s )
{
    emit sgnValueRecieved( s );
    return parseAnswer( s );
}

//-------------------------------------

ProcessVariable T2CManager::probeVariable( quint64 idf, quint64 timeout )
{
    emit sgnExecCmd( QString( "ANM 0 TST %1" ).arg( idf ) );

    ProcessVariable pv;
    pv.init();
    if( checkTimeout( timeout ) )
    {
        pv = parseAnswer( qmm->outStr );
    }
    int cp=1;
    return pv;
}

//-------------------------------------

void T2CManager::subscribe( quint64 idf, bool inquiry )
{
    if( inquiry )
        emit sgnExecCmd( QString( "ANM 0 ORG %1" ).arg( idf ) );
    else
        emit sgnExecCmd( QString( "ANM 0 DYN %1" ).arg( idf ) );
}

//-------------------------------------

void T2CManager::unsubscribe( quint64 idf )
{
    emit sgnExecCmd( QString( "ANM 0 END %1" ).arg( idf ) );
}

//-------------------------------------

void T2CManager::waitForValueChange( quint64 idf, quint64 waitTime )
{
    if( PVs.contains( idf ) )
    {
        wait( waitTime );
    }
}




